package com.weijian.service.impl;

import com.weijian.common.result.ApiResponse;
import com.weijian.dal.entity.MatchDetail;
import com.weijian.dal.entity.Route;
import com.weijian.dal.entity.Shipment;
import com.weijian.dal.entity.Task;
import com.weijian.dal.enums.TaskStatus;
import com.weijian.dto.match.MatchResultData;
import com.weijian.dto.match.RouteShipmentDTO;
import com.weijian.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

@Slf4j
@Service
public class AlgorithmExecutionServiceImpl implements AlgorithmExecutionService {

    @Value("${algorithm.exe.path:cmake-build-debug/stable_match.exe}")
    private String exePath;

    @Autowired
    private TaskService taskService;

    @Autowired
    private CsvDataService csvDataService;

    @Autowired
    private MatchResultService matchResultService;

    @Autowired
    private RouteService routeService;

    @Autowired
    private ShipmentService shipmentService;

    @Override
    public ApiResponse<String> executeMatchingAlgorithm(String taskNo) {
        try {
            // 1. 根据taskNo获取dataId（batchId）
            Task task = taskService.getByTaskNo(taskNo);
            if (task == null) {
                return ApiResponse.badRequest("任务不存在: " + taskNo);
            }
            Integer dataId = task.getDataId();
            log.info("开始执行算法: taskNo={}, dataId={}", taskNo, dataId);

            // 2. 获取当前工作目录
            Path currentDir = Paths.get("").toAbsolutePath();
            currentDir = currentDir.resolve("src/main/resources");

            // 3. 获取批次的专属数据目录和静态数据目录
            Path batchDataDir = currentDir.resolve("cmake-build-debug/data/" + dataId);
            Path staticDataDir = currentDir.resolve("cmake-build-debug/data");

            // 4. 定义必要的输入文件路径
            // 路线和货物文件：动态路径（按批次隔离）
            Path routeFile = batchDataDir.resolve("route.csv");
            Path shipmentFile = batchDataDir.resolve("shipment.csv");
            // 网络和合作参数文件：静态路径（所有批次共用）
            Path networkFile = staticDataDir.resolve("network.csv");
            Path cooperationFile = staticDataDir.resolve("cooperation_parameter.csv");

            // 5. 检查必要的输入文件是否存在
            if (!Files.exists(routeFile)) {
                return ApiResponse.badRequest("路线数据文件不存在: " + routeFile + "，请先上传路线CSV文件");
            }

            if (!Files.exists(shipmentFile)) {
                return ApiResponse.badRequest("货物数据文件不存在: " + shipmentFile + "，请先上传货物CSV文件");
            }

            // 检查静态文件是否存在
            if (!Files.exists(networkFile)) {
                return ApiResponse.badRequest("网络文件不存在: " + networkFile);
            }

            if (!Files.exists(cooperationFile)) {
                return ApiResponse.badRequest("合作参数文件不存在: " + cooperationFile);
            }

            Path exePathObj = currentDir.resolve(exePath);
            if (!Files.exists(exePathObj)) {
                return ApiResponse.badRequest("算法可执行文件不存在: " + exePathObj);
            }

            // 构建输出文件路径（每个批次独立目录）
            Path outputDir = currentDir.resolve("cmake-build-debug/result/" + dataId);
            if (!Files.exists(outputDir)) {
                Files.createDirectories(outputDir);
            }
            Path outputFile = outputDir.resolve("stable_matching.csv");

            // 构建执行命令
            List<String> command = Arrays.asList(
                    exePathObj.toString(),
                    networkFile.toString(),
                    shipmentFile.toString(),
                    routeFile.toString(),
                    cooperationFile.toString(),
                    outputFile.toString()
            );

            // 执行算法
            ProcessBuilder processBuilder = new ProcessBuilder(command);
            processBuilder.redirectErrorStream(true);

            Process process = processBuilder.start();

            // 获取输出
            StringBuilder output = new StringBuilder();
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(process.getInputStream()))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    output.append(line).append("\n");
                }
            }

            // 等待进程完成
            int exitCode = process.waitFor();

            // 根据进程返回码判断执行结果
            if (exitCode != 0) {
                return ApiResponse.internalError(
                        "算法执行失败，返回码: " + exitCode + ", 输出: " + output);
            }

            // 检查输出文件是否存在
            if (!Files.exists(outputFile)) {
                return ApiResponse.internalError("算法执行完成，但未生成输出文件: " + outputFile);
            }

            // 解析生成的CSV文件并保存到数据库
            try {
                // 直接解析CSV文件
                MatchResultData matchResultData = csvDataService.parseMatchResultCsv(outputFile.toFile(), dataId);

                // 保存匹配结果到数据库
                ApiResponse<Integer> saveResult = csvDataService.saveMatchResultData(matchResultData, taskNo, dataId);

                if (saveResult.getCode() == 200) {
                    // 计算并更新路线剩余容量
                    if (matchResultData.getMatchDetails() != null && !matchResultData.getMatchDetails().isEmpty()) {
                        updateRouteRemainingCapacity(matchResultData.getMatchDetails(), dataId);
                    }
                    return ApiResponse.success("算法执行完成，返回码: " + exitCode + "，结果已保存到数据库，匹配结果ID: " + saveResult.getData());
                } else {
                    return ApiResponse.internalError("保存匹配结果失败: " + saveResult.getMessage());
                }
            } catch (Exception e) {
                return ApiResponse.internalError("解析并保存结果时发生错误: " + e.getMessage());
            }

        } catch (Exception e) {
            return ApiResponse.internalError("执行算法时发生错误: " + e.getMessage());
        }
    }


    /**
     * 更新路线剩余容量
     * @param matchDetails 匹配详情列表
     */
    private void updateRouteRemainingCapacity(List<MatchDetail> matchDetails, Integer dadaId) {
        try {
            // 获取所有涉及的路线ID
            List<Integer> routeIds = matchDetails.stream()
                    .map(MatchDetail::getRouteId)
                    .filter(routeId -> routeId != -1) // 过滤掉Self分配的情况
                    .distinct()
                    .collect(Collectors.toList());

            if (routeIds.isEmpty()) {
                return;
            }

            // 批量查询路线的货物ID
            List<RouteShipmentDTO> routeShipmentDTOs = matchResultService.getShipmentIdsByRouteIds(routeIds, dadaId);

            // 记录查询参数
            log.info("开始查询路线信息，routeIds数量: {}, 是否按dataId过滤: {}", routeIds.size(), dadaId != null);

            // 获取所有相关路线
            List<Route> routes = routeService.lambdaQuery()
                    .eq(dadaId != null, Route::getDataId, dadaId)
                    .in(Route::getRouteId, routeIds)
                    .list();

            // 记录查询结果
            log.info("路线查询完成，实际查询到的路线数量: {}", routes.size());


            // 更新每条路线的剩余容量
            for (Route route : routes) {
                // 查找该路线的货物ID
                List<Integer> shipmentIds = routeShipmentDTOs.stream()
                        .filter(dto -> dto.getRouteId().equals(route.getRouteId()))
                        .findFirst()
                        .map(RouteShipmentDTO::getShipmentIds)
                        .orElse(null);

                if (shipmentIds != null && !shipmentIds.isEmpty()) {
                    // 获取货物详情
                    List<Shipment> shipments = shipmentService.lambdaQuery().eq(Shipment::getDataId, dadaId).in(Shipment::getShipmentId, shipmentIds).list();

                    // 计算货物需求量之和
                    int totalDemand = shipments.stream()
                            .mapToInt(Shipment::getDemand)
                            .sum();

                    // 计算剩余容量 = 路线容量 - 货物需求量之和
                    if (route.getCapacity() != null && route.getCapacity() > 0) {
                        int remainingCapacity = route.getCapacity() - totalDemand;
                        // 确保剩余容量不为负数
                        remainingCapacity = Math.max(remainingCapacity, 0);
                        route.setRemainingCapacity(remainingCapacity);

                        // 更新路线
                        routeService.updateById(route);
                    }
                }
            }
        } catch (Exception e) {
            // 忽略更新剩余容量时的错误，不影响主要流程
            e.printStackTrace();
        }
    }

    @Async("algorithmExecutor")
    @Override
    public CompletableFuture<ApiResponse<String>> executeMatchingAlgorithmAsync(String taskNo) {
        // 更新任务状态为运行中
        try {
            taskService.updateTaskStatus(taskNo, TaskStatus.RUNNING);
        } catch (NumberFormatException e) {
            // 忽略错误，继续执行
        }
        ApiResponse<String> result = executeMatchingAlgorithm(taskNo);
        // 更新任务状态
        try {
            if (result.getCode() == 200) {
                taskService.updateTaskStatus(taskNo, TaskStatus.SUCCESS, result.getData());
            } else {
                taskService.updateTaskStatus(taskNo, TaskStatus.FAILED, result.getMessage());
            }
        } catch (NumberFormatException e) {
            // 忽略错误，继续执行
        }
        // 通知任务状态
        taskService.sendTaskStatus(taskNo, result);
        return CompletableFuture.completedFuture(result);
    }
}